package com.mangix.http;

import com.mangix.core.MangixNode;
import org.json.simple.JSONValue;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Map;

/**
 * Created by Ahan on 2014/5/21.
 */
public class MangixCommonServlet extends HttpServlet {
    private MangixServer server;

    public MangixCommonServlet(MangixServer server) {
        this.server = server;
    }

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        String requestURI = req.getRequestURI();
        if (requestURI == null) {
            resp.sendError(404);
            return;
        }
        String method = requestURI.substring(1);
        if (method.equals("")) {
            resp.sendError(404);
            return;
        }
        PrintWriter out = null;
        switch (method) {
            case "closet-preceding-finger":
                String strID = req.getParameter("id");
                long id = Long.parseLong(strID);
                try {
                    MangixNode node = this.server.getNode();
                    MangixNode[] nodes = node.closetPrecedingFinger(id);
                    out = resp.getWriter();
                    out.printf("{\"hostname\":\"%s\", \"port\":%d, \"successor\":{\"hostname\":\"%S\", \"port\":%d}}", nodes[0].getHostName(), nodes[0].getPort(), nodes[1].getHostName(), nodes[1].getPort());
                    out.flush();

                } catch (Exception e) {
                    resp.sendError(500, e.getMessage());
                } finally {
                    if (out != null) {
                        out.close();
                    }
                }
                break;
            case "successor":
                try {
                    MangixNode localNode = this.server.getNode();
                    MangixNode node = localNode.getSuccessor();
                    out = resp.getWriter();
                    out.printf("{\"hostname\":\"%s\", \"port\":%d}", node.getHostName(), node.getPort());
                    out.flush();
                } catch (Exception e) {
                    resp.sendError(500, e.getMessage());
                } finally {
                    if (out != null) {
                        out.close();
                    }
                }
                break;
            case "predecessor":
                try {
                    MangixNode localNode = this.server.getNode();
                    MangixNode predecessor = localNode.getPredecessor();
                    out = resp.getWriter();
                    out.printf("{\"hostname\":\"%s\", \"port\":%d}", predecessor.getHostName(), predecessor.getPort());
                    out.flush();
                } catch (Exception e) {
                    resp.sendError(500, e.getMessage());
                } finally {
                    if (out != null) {
                        out.close();
                    }
                }
                break;
            case "successor-list":
                try {
                    MangixNode localNode = this.server.getNode();
                    ArrayList<MangixNode> successorList = localNode.getSuccessorList();
                    out = resp.getWriter();
                    out.printf("{\"successor-list\":[");
                    for (int i = 0; i < successorList.size(); i++) {
                        if (i == 0)
                            out.printf("{\"hostname\":\"%s\", \"port\":%d}", successorList.get(i).getHostName(), successorList.get(i).getPort());
                        else
                            out.printf(",{\"hostname\":\"%s\", \"port\":%d}", successorList.get(i).getHostName(), successorList.get(i).getPort());
                    }
                    out.printf("]}");
                    out.flush();
                    out.close();
                } catch (Exception e) {
                    resp.sendError(500, e.getMessage());
                } finally {
                    if (out != null) {
                        out.close();
                    }
                }
                break;
            case "predecessor-list":
                try {
                    MangixNode localNode = this.server.getNode();
                    ArrayList<MangixNode> predecessorList = localNode.getPredecessorList();
                    out = resp.getWriter();
                    out.printf("{\"predecessor-list\":[");
                    for (int i = 0; i < predecessorList.size(); i++) {
                        if (i == 0)
                            out.printf("{\"hostname\":\"%s\", \"port\":%d}", predecessorList.get(i).getHostName(), predecessorList.get(i).getPort());
                        else
                            out.printf(",{\"hostname\":\"%s\", \"port\":%d}", predecessorList.get(i).getHostName(), predecessorList.get(i).getPort());
                    }
                    out.printf("]}");
                    out.flush();
                } catch (Exception e) {
                    resp.sendError(500, e.getMessage());
                } finally {
                    if (out != null) {
                        out.close();
                    }
                }
                break;
            case "is-active":
                resp.setStatus(200);
                resp.getWriter().close();
            default:
                break;
        }


    }

    @Override
    protected void doPut(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        String requestURI = req.getRequestURI();
        if (requestURI == null) {
            resp.sendError(404);
            return;
        }
        String method = requestURI.substring(1);
        if (method.equals("")) {
            resp.sendError(404);
        }
        InputStream in = null;
        switch (method) {
            case "predecessor": {
                try {
                    in = req.getInputStream();
                    byte[] buffer = new byte[1024];
                    int startPosition = 0, readLength = 0;
                    while ((readLength = in.read(buffer, startPosition, buffer.length)) != -1) {
                        startPosition += readLength;
                    }
                    String jsonString = new String(buffer, 0, startPosition);
                    Map map = (Map) JSONValue.parse(jsonString);
                    String hostname = map.get("hostname").toString();
                    int port = Integer.parseInt(map.get("port").toString());
                    MangixNode localNode = this.server.getNode();
                    localNode.notify(MangixNode.createNode(hostname, port));
                } catch (Exception e) {
                    resp.sendError(500, e.getMessage());
                } finally {
                    if (in != null) {
                        in.close();
                    }
                }
                break;
            }
//            case "finger-table": {
//                try {
//                    in = req.getInputStream();
//                    byte[] buffer = new byte[1024];
//                    int startPosition = 0, readLength = 0;
//                    while ((readLength = in.read(buffer, startPosition, buffer.length)) != -1) {
//                        startPosition += readLength;
//                    }
//                    String jsonString = new String(buffer, 0, startPosition);
//                    Map map = (Map) JSONValue.parse(jsonString);
//                    String hostname = map.get("hostname").toString();
//                    int port = Integer.parseInt(map.get("port").toString());
//                    int i = Integer.parseInt(map.get("i").toString());
//                    MangixNode localNode = this.server.getNode();
//                    localNode.updateFingerTable(new MangixNode(hostname, port, this.server.getConfig()), i);
//                } catch (Exception e) {
//                    resp.sendError(500, e.getMessage());
//                } finally {
//                    if (in != null) {
//                        in.close();
//                    }
//                }
//                break;
//            }
            default:
                break;
        }

    }

}
